package org.jeecg.modules.miniAppCustomerEndPoint.service;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.http.HttpClient;
import com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter;
import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.service.billdownload.BillDownloadService;
import com.wechat.pay.java.service.billdownload.BillDownloadServiceExtension;
import com.wechat.pay.java.service.billdownload.DigestBillEntity;
import com.wechat.pay.java.service.billdownload.model.*;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.RandomUtils;
import okhttp3.HttpUrl;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.IpUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.hc.entity.HcWxPay;
import org.jeecg.modules.hc.entity.HcWxPayRefund;
import org.jeecg.modules.hc.mapper.HcWxPayMapper;
import org.jeecg.modules.hc.pcWxPay.config.WeChatConfig;
import org.jeecg.modules.hc.service.IHcWxPayService;
import org.jeecg.modules.miniAppCustomerEndPoint.entity.JxOrderDo;
import org.jeecg.modules.miniAppCustomerEndPoint.entity.JxWxPayVo;
import org.jeecg.modules.miniAppCustomerEndPoint.mapper.JxOrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Description: 微信支付
 * @Author: jeecg-boot
 * @Date: 2023-01-07
 * @Version: V1.0
 */
@Slf4j
@Service
public class JxWxPayServiceImpl {
    @Autowired
    private WxPayService payService;

    @Value("${wx.pay.privateKeyPath}")
    private String privateKeyPath ;

    public JxWxPayVo pay(String userId, String openId, String orderId, String description, Integer total) throws WxPayException {

//        String notifyUrl = "https://btprint.yongshantuan.cn:3389/jeecg-boot/jx/jxOrderPay/notify";
        String notifyUrl = "https://btprint.yongshantuan.cn:8085/jeecg-boot/jx/jxOrderPay/notify";
//        String notifyUrl = "https://customer.qiyetuancan.com:3389/jeecg-boot/jx/jxOrderPay/notify";
        String currency = "CNY";

//        openId = "oP3a362aeLUnznyb_g6-qm38QQmM"; // 大鹏的微信在 壹食之间 小程的 openid, 请求参数中的 payer.openid
        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        request.setAppid("wx452cd162d2928e07"); // jx  壹食之间 小程的 app id
        request.setMchid("1659232319"); // jx 小番茄商户 merchant id
        request.setDescription(description);
        request.setOutTradeNo(orderId);
        request.setNotifyUrl(notifyUrl);

        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, 1);
        request.setTimeExpire(DateUtil.format(instance.getTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"));

        //构建金额信息
        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
        //设置币种信息
        amount.setCurrency(currency);
        //设置金额
        amount.setTotal(total);

        request.setAmount(amount);

        JxWxPayVo wxPay = new JxWxPayVo().setUserId(userId).setDescription(description).setOutTradeNo(orderId)
                .setAmountCurrency(currency).setAmountTotal(total);

        request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(openId));
        WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = this.payService.createOrderV3(TradeTypeEnum.JSAPI, request);
        log.info("prepay: {}", jsapiResult);

        wxPay.setAppid(request.getAppid()).setMchId(request.getMchid()).setTimeStamp(jsapiResult.getTimeStamp()).setNonceStr(jsapiResult.getNonceStr())
                .setPackageValue(jsapiResult.getPackageValue()).setSignType(jsapiResult.getSignType()).setPaySign(jsapiResult.getPaySign());

        return wxPay;
    }

    public WxPayOrderQueryV3Result queryPayResult(String orderId) {
        WxPayOrderQueryV3Result wxPayOrderQueryV3Result = null;
        try {
            wxPayOrderQueryV3Result = this.payService.queryOrderV3(null, orderId);
        } catch (WxPayException e) {
            throw new RuntimeException(e);
        }
        System.out.println(wxPayOrderQueryV3Result);

        return wxPayOrderQueryV3Result;
    }


    public HcWxPayRefund refund(String outTradeNo, String userId, Integer total, Integer refund) throws WxPayException {
        String outRefundNo = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + RandomUtils.getRandomStr();
        String notifyUrl = "https://www.weixin.qq.com/wxpay/pay.php";
        String currency = "CNY";
        String reason = "取消订单";

        WxPayRefundV3Request request = new WxPayRefundV3Request();
        request.setOutTradeNo(outTradeNo);
        request.setOutRefundNo(outRefundNo);
        request.setReason(reason);
        request.setNotifyUrl(notifyUrl);

        //构建金额信息
        WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
        //设置币种信息
        amount.setCurrency(currency);
        //设置金额
        amount.setTotal(total);
        amount.setRefund(refund);

        request.setAmount(amount);

        HcWxPayRefund wxPayRefund = new HcWxPayRefund().setUserId(userId).setOutTradeNo(outTradeNo)
                .setOutRefundNo(outRefundNo).setReason(reason).setRefund(refund)
                .setNotifyUrl(notifyUrl).setAmountTotal(total).setAmountCurrency(currency);

        WxPayRefundV3Result wxPayRefundV3Result = this.payService.refundV3(request);
        wxPayRefund.setRefundId(wxPayRefundV3Result.getRefundId()).setChannel(wxPayRefundV3Result.getChannel());

        return wxPayRefund;
    }

    /**
     * 调用 关闭支付交易 接口，https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/close-order.html
     * @param outTradeNo
     * @return
     */
    public Result<?> closeTransaction(String outTradeNo) {

        WxPayOrderCloseV3Request request = new WxPayOrderCloseV3Request();
        request.setOutTradeNo(outTradeNo);
        try{
            // closeOrderV3() 方法无返回值，取消支付 请求是否成功，通过抛出的异常中的 错误码来判断
            // 若不抛出异常，则表示成功
            this.payService.closeOrderV3(request);
            log.info("发起支付 取消成功");
            return Result.ok("支付取消成功");
        } catch (WxPayException ex) {
            log.info("发起支付 取消失败：{}", ex);
            return Result.error("支付取消失败", ex);
        }
    }


    /**
     * 参考链接： https://github.com/wechatpay-apiv3/wechatpay-java ，调用业务请求接口 章节 java示例
     *
     * @param billDate
     * @return
     */
    public Result<?> queryTransactionBill(String billDate) {

        try {

            Config config =
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId("1659232319")
                            .privateKeyFromPath(privateKeyPath)
                            .merchantSerialNumber("1B5D1FC41283EB90A130458726C49459318E15CC")
                            .apiV3Key("JixinKeJiCor20231224CorJixinKeJi")
                            .build();
            BillDownloadService billDownloadService = new BillDownloadService.Builder().config(config).build();
            GetTradeBillRequest tradeBillRequest = new GetTradeBillRequest();
            tradeBillRequest.setBillDate(billDate);
            tradeBillRequest.setBillType(BillType.ALL);
            tradeBillRequest.setTarType(TarType.GZIP);

            BillDownloadServiceExtension downloadServiceExtension = new BillDownloadServiceExtension.Builder().config(config).build();
            DigestBillEntity billEntity2 =  downloadServiceExtension.getTradeBill(tradeBillRequest);
            InputStream inputStream = billEntity2.getInputStream();
            String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
            log.info("-------------- bill ------------- result: {}", result);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 参考链接： https://github.com/wechatpay-apiv3/wechatpay-java ，调用业务请求接口 章节 java示例
     *
     * @param billDate
     * @return
     */
    public Result<?> queryFundBill(String billDate) {

        try {
            Config config =
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId("1659232319")
                            .privateKeyFromPath(privateKeyPath)
                            .merchantSerialNumber("1B5D1FC41283EB90A130458726C49459318E15CC")
                            .apiV3Key("JixinKeJiCor20231224CorJixinKeJi")
                            .build();
            BillDownloadService billDownloadService = new BillDownloadService.Builder().config(config).build();
            GetFundFlowBillRequest fundBillRequest = new GetFundFlowBillRequest();
            fundBillRequest.setBillDate(billDate);
            fundBillRequest.setAccountType(AccountType.BASIC);  // basic 基本账户， operation 运营账户，fees 手续费账户
            fundBillRequest.setTarType(TarType.GZIP);

            BillDownloadServiceExtension downloadServiceExtension = new BillDownloadServiceExtension.Builder().config(config).build();
            DigestBillEntity billEntity2 =  downloadServiceExtension.getFundFlowBill(fundBillRequest);
            InputStream inputStream = billEntity2.getInputStream();
            String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
            log.info("-------------- fund ------------- result: {}", result);

        }  catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


}
